#!/bin/bash

#日志
#1.0.0#
#a.打包基本功能
#b.增加生成支付回调功能
#
#

#脚本文件包含
# . ./0_payCallback/getPayURL.sh

# 工作目录
WDir='.'
readonly WDir

# plist文件管理者
PlistBuddy='/usr/libexec/PlistBuddy'
readonly PlistBuddy
# 证书管理
Security='/usr/bin/security'
readonly Security
# 签名管理
codesign='/usr/bin/codesign'
readonly codesign

# ipa资源路径
ipaPath="${WDir}/0_ipa"
readonly ipaPath
# 渠道资源路径
channelPath="${WDir}/0_Channel"
readonly channelPath

# plist文件开头
plistPrefix='<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict/></plist>'
readonly plistPrefix

# ipa中Info.plist文件路径
ipaPlist="${WDir}/Payload/*.app/Info.plist"
readonly ipaPlist

# 图片资源路径
imagePath="${WDir}/Assets"
readonly imagePath

# packConfig.plist 打包缓存配置
packConfig="${WDir}/packConfig.plist"
readonly packConfig
# ipa包列表
ipaList='ipaList'
readonly ipaList
# 渠道列表
channelList='channelList'
readonly channelList

# SDK配置参数文件路径
plistConfigPath='plistConfigPath'
readonly plistConfigPath

# mobileprovision文件
mobileprovisionPlist="${WDir}/mobileprovision.plist"
readonly mobileprovisionPlist

# entitlements.plist
entitlementsPlist="${WDir}/entitlements.plist"
readonly entitlementsPlist

# payCallbackConfig
payCallbackConfig="payCallbackConfig.plist"
readonly payCallbackConfig

# 创建打包缓存配置文件
create_packConfig()
{
	# 删除旧缓存文件
	if [[ -e $packConfig ]]; then
		rm -rf $packConfig
	fi
	# 新建缓存文件
	echo $plistPrefix > $packConfig
}


# 显示ipa文件列表
show_ipaList()
{
	if [[ -e $ipaPath ]]; then
		$PlistBuddy -c "Delete :${ipaList}" $packConfig
		$PlistBuddy -c "Add :${ipaList} array" $packConfig
		echo 'ipa包列表:'
		# 项目编号
		i=0
		for ipaFile in $(ls $ipaPath/*.ipa); do
			ipaFile=${ipaFile##*/}
			ipaFile=${ipaFile%.*}
			$PlistBuddy -c "Add :${ipaList}:$i string ${ipaFile}" $packConfig
			echo "[`expr $i + 1`].$ipaFile"
			i=`expr $i + 1`
		done
		if [[ $i -eq 0 ]]; then
			ipaName=$ipaFile
			echo "\"${ipaPath}\"路径下没有ipa资源"
			continue
		fi
	else
		mkdir $ipaPath
		echo "[错误]:请把ipa文件放入\"${ipaPath}\"路径下"
		continue
	fi
}
# 解压要操作ipa文件
open_ipaFile()
{
	show_ipaList

	read -p '输入需要操作的ipa文件序号:' number
	number=`expr $number - 1`
	ipaName=`$PlistBuddy -c "Print :${ipaList}:$number" $packConfig`

	# 判断操作文件是否存在
	if [[ -e $ipaPath/${ipaName}.ipa ]]; then
		# 保存正在处理的ipa文件名到本地缓存配置
		$PlistBuddy -c "Add ipaName string $ipaName" $packConfig
		# 删除已存在的Payload
		if [[ -e ${WDir}/Payload ]]; then
			rm -rf ${WDir}/Payload
		fi
		# 解压ipa到当前目录
		unzip -d $WDir $ipaPath/${ipaName}.ipa
		# 删除__MACOSX垃圾文件
		rm -rf ${WDir}/__MACOSX
	else
		echo '[错误]:没有匹配到要操作的ipa文件'
		continue
	fi
}


# 显示渠道列表
show_channleList()
{
	if [[ -e $channelPath ]]; then
		$PlistBuddy -c "Delete :${channelList}" $packConfig
		$PlistBuddy -c "Add :${channelList} array" $packConfig
		echo '渠道列表:'
		# 项目编号
		i=0
		for channelFile in $(ls $channelPath/*.zip); do
			channelFile=${channelFile##*/}
			channelFile=${channelFile%.*}
			$PlistBuddy -c "Add :${channelList}:$i string ${channelFile}" $packConfig
			echo "[`expr $i + 1`].$channelFile"
			i=`expr $i + 1`
		done

		if [[ $i -eq 0 ]]; then
			echo "\"${channelPath}\"路径下没有渠道SDK资源"
			continue;
		fi
	else
		mkdir $channelPath
		echo "[错误]:请把渠道SDK资源文件放入\"${channelPath}\"路径下"
		continue
	fi
}
# 解压要操作的渠道文件
open_channelSDK()
{
	show_channleList

	read -p '输入需要操作的渠道序号:' number
	number=`expr $number - 1`
	channelName=`$PlistBuddy -c "Print :${channelList}:$number" $packConfig`

	if [[ -e $channelPath/${channelName}.zip ]]; then
		# 保存正在处理的渠道名到本地缓存配置
		$PlistBuddy -c "Add channelName string $channelName" $packConfig
		if [[ -e ${WDir}/$channelName ]]; then
			# 删除已存在的渠道文件夹
			rm -rf ${WDir}/$channelName
		fi
		# 解压对应渠道资源
		unzip -d $WDir $channelPath/${channelName}.zip 
		# 删除__MACOSX垃圾文件
		rm -rf ${WDir}/__MACOSX
	else
		echo '[错误]:没有匹配到需要操作的渠道名'
		continue
	fi
}


# 集成SDK资源文件到ipa包
importSDK()
{
	echo '**********集成SDK资源*************'
	open_ipaFile
	open_channelSDK
	# 导入framework
	if [[ -e ${WDir}/Payload/*.app/Frameworks ]]; then
		pass
	else
		mkdir 'Payload/*.app/Frameworks'
	fi
	mv -n ${WDir}/${channelName}/Frameworks/* ${WDir}/Payload/*.app/Frameworks/
	# 导入渠道资源到IPA,重复不替换
	mv -n ${WDir}/${channelName}/* ${WDir}/Payload/*.app/
}

# 合并Plist信息
Merge_plist()
{
	echo '****导入白名单,配置[URL Types]****'
	# 判断是否存在Info.plist
	if [[ -e ${WDir}/${channelName}/Info.plist ]]; then
		echo 'a.合并信息'
		# 合并渠道Info.plist配置到ipa包Info.plist配置,重复不会替换
		$PlistBuddy -c "Merge ${WDir}/${channelName}/Info.plist" $ipaPlist

		# 添加渠道LSApplicationQueriesSchemes,plist文件中必须有这个数组
		echo 'b.导入白名单'
		for (( i = 0; i < 99; i++ )); do
			LSApplicationQueriesSchemes=`$PlistBuddy -c "Print :LSApplicationQueriesSchemes:$i" ${WDir}/${channelName}/Info.plist`
			if [[ $LSApplicationQueriesSchemes ]]; then
				$PlistBuddy -c "Add :LSApplicationQueriesSchemes:0 string $LSApplicationQueriesSchemes" $ipaPlist
			else
				break
			fi
		done

		echo 'c.配置[URL Types]:'
		# 添加渠道URL Types,plist文件中必须有这个数组
		for (( i = 0; i < 99; i++ )); do
 			CFBundleURL=`$PlistBuddy -c "Print :CFBundleURLTypes:$i" ${WDir}/${channelName}/Info.plist`
			# echo -e "\n$CFBundleURL\n"
			if [[ ! $CFBundleURL ]]; then
				break
			fi

			#读取信息
			CFBundleTypeRole=`$PlistBuddy -c "Print :CFBundleURLTypes:$i:CFBundleTypeRole" ${WDir}/${channelName}/Info.plist`
			CFBundleURLName=`$PlistBuddy -c "Print :CFBundleURLTypes:$i:CFBundleURLName" ${WDir}/${channelName}/Info.plist`
			CFBundleURLSchemes=`$PlistBuddy -c "Print :CFBundleURLTypes:$i:CFBundleURLSchemes:0" ${WDir}/${channelName}/Info.plist`

			echo "提示：$CFBundleURLSchemes"
			read -p '按提示输入[URL Schemes]:' URLScheme
	
			if [[ $URLScheme ]]; then
				#添加
				$PlistBuddy -c "Add :CFBundleURLTypes:0 dict" $ipaPlist
				if [[ $CFBundleTypeRole ]]; then
					$PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleTypeRole string $CFBundleTypeRole" $ipaPlist
				fi
				if [[ $CFBundleURLName ]]; then
					$PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLName string $CFBundleURLName" $ipaPlist
				fi
				#添加
				$PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes array" $ipaPlist
				$PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes:0 string $URLScheme" $ipaPlist
			else
				i=`expr $i - 1`
			fi
		done
	else
		echo '没有找到渠道Info.plist文件'
		continue
	fi
}

# 配置plist参数信息
setPlistParameter()
{
	echo '******配置plist信息*******'
	# 配置Info.plist包名等信息
	echo '****提示:配置应用信息,直接回车使用默认值****'
	displayName=`$PlistBuddy -c "Print :CFBundleDisplayName" $ipaPlist`
	read -p "[应用名称(默认:${displayName})]:" input
	if [[ $input ]]; then
		displayName=$input
	fi
	$PlistBuddy -c "Set :CFBundleDisplayName $displayName" $ipaPlist
	$PlistBuddy -c "Set :CFBundleName $displayName" $ipaPlist

	bundleID=`$PlistBuddy -c "Print :CFBundleIdentifier" $ipaPlist`
	read -p "[应用BundleID(默认:$bundleID)]:" input
	if [[ $input ]]; then
		bundleID=$input
	fi
	$PlistBuddy -c "Set :CFBundleIdentifier $bundleID" $ipaPlist

	version=`$PlistBuddy -c "Print :CFBundleShortVersionString" $ipaPlist`
	read -p "[应用版本(默认:$version)]:" input
	if [[ $input ]]; then
		version=$input
	fi
	$PlistBuddy -c "Set :CFBundleShortVersionString $version" $ipaPlist
	
	bundle=`$PlistBuddy -c "Print :CFBundleVersion" $ipaPlist`
	read -p "[Bundle(默认:$bundle)]:" input
	if [[ $input ]]; then
		bundle=$input
	fi
	$PlistBuddy -c "Set :CFBundleVersion $bundle" $ipaPlist
	
	# 合并plist信息
	Merge_plist

	# 导出ipa包相关plist文件到配置目录,手动填写参数
	CFBundleExecutable=$($PlistBuddy -c "Print :CFBundleExecutable" $ipaPlist)
	appPath="${WDir}/Payload/${CFBundleExecutable}.app"
	
	echo '****提示:按文件名提示配置渠道文件夹中的参数文件****'
	for (( i = 0; i < 99 ; i++ )); do
		plistFileName=`$PlistBuddy -c "Print :plistConfigPath:$i" ${WDir}/${channelName}/Info.plist`
		if [[ $plistFileName ]]; then
			echo "需要配置的参数文件:$plistFileName"
			# 移动指定文件
			mv $appPath/$plistFileName ${WDir}/${channelName}/
		else
			break
		fi
	done

	read -p '确认已配置好各参数文件(Y/N):' YN
	if [ "$YN" == "y" ] || [ "$YN" == 'Y' ]; then
		# 存储配置文件中的服务器和渠道号
		server_type=`$PlistBuddy -c "Print :server_config:server_type" ${WDir}/${channelName}/app_config.plist`
		$PlistBuddy -c "Add server_type string $server_type" $packConfig
		server_channel=`$PlistBuddy -c "Print :server_config:server_channel" ${WDir}/${channelName}/app_config.plist`
		$PlistBuddy -c "Add server_channel string $server_channel" $packConfig

		# 遍历移动已配置好的参数文件
		for (( i = 0; i < 99 ; i++ )); do
			plistFileName=`$PlistBuddy -c "Print :plistConfigPath:$i" ${WDir}/${channelName}/Info.plist`
			if [[ $plistFileName ]]; then
				#获取对应文件路径
				for file in $(ls ${WDir}/${channelName}/*.plist); do
					file=${file##*/}
					if [[ $plistFileName == *$file ]]; then
						# echo $file
						# path=${plistFileName%$file}
						# echo $path
						# 移动到对应目录下
						mv ${WDir}/${channelName}/$file $appPath/$plistFileName
					fi
				done
			else
				break
			fi
		done
	fi
}

# 导入图片资料
importAssets()
{
	echo '******导入图片资源*********'
	if [[ -e $imagePath ]]; then
		# 删除已存在的图片资源文件夹
		rm -rf $imagePath
	fi
	# 创建图片资源文件夹
	mkdir $imagePath

	bundleID=`$PlistBuddy -c "Print :CFBundleIdentifier" $ipaPlist`

	read -p "确认将准备好的图片资源放到[${imagePath}]文件夹中(Y/N):" YN
	if [ "$YN" == 'y' ] || [ "$YN" == 'Y' ]; then
		mkdir $imagePath/out_Assets
		# 导入图片资源到IPA,重复会直接替换
		if [[ -e $imagePath/Assets.xcassets ]]; then
			`/Applications/Xcode.app/Contents/Developer/usr/bin/actool --output-format human-readable-text --notices --warnings --export-dependency-info ${imagePath}/assetcatalog_dependencies --output-partial-info-plist ${imagePath}/assetcatalog_generated_info.plist --app-icon AppIcon --launch-image LaunchImage --compress-pngs --enable-on-demand-resources YES --sticker-pack-identifier-prefix ${bundleID}.sticker-pack. --target-device iphone --target-device ipad --minimum-deployment-target 8.0 --platform iphoneos --product-type com.apple.product-type.application --compile ${imagePath}/out_Assets ${imagePath}/Assets.xcassets`
		else
			echo '[警告]:需要放入图片资源'
			continue
		fi
		mv ${imagePath}/out_Assets/* ${WDir}/Payload/*.app
	else
		echo '[警告]:需要放入图片资源'
		continue
	fi
}

# ipa包重签函数
resign_ipa()
{
	# 判断需要解压
	if [[ -e ${WDir}/Payload ]]; then
		#statements
		echo "*********开始签名**********"
	else
		echo '没有找到Payload文件夹'
		continue
	fi

	# 获取渠道商
	if [[ $channelName ]]; then
		echo ''
	else
		open_channelSDK
	fi

	#获取当前目录的证书文件
	echo '证书描述文件列表:'
	i=0
	for file in $(ls ${WDir}/*.mobileprovision); do
		i=`expr $i + 1`
		file=${file##*/}
		file=${file%.*}
		echo "[$i] - $file"
	done

	if [[ $i -gt 1 ]]; then
		read -p '请复制输入需要的描述文件名:' mobileprovisionFile
	elif [[ $i -eq 1 ]]; then
		mobileprovisionFile=$file
	else
		echo '[错误]:没有找到描述文件'
		continue
	fi

	if [[ -e ${WDir}/${mobileprovisionFile}.mobileprovision ]]; then
	
		#导出证书描述信息到plist
		echo $plistPrefix > ${WDir}/$mobileprovisionPlist
		`security cms -D -i ${WDir}/${mobileprovisionFile}.mobileprovision > ${WDir}/${mobileprovisionPlist}`

		#导出打包参数
		# echo $plistPrefix > ${WDir}/$entitlementsPlist
		`$PlistBuddy -x -c "Print :Entitlements" ${WDir}/$mobileprovisionPlist > ${WDir}/$entitlementsPlist`

		#使用完删除
		rm -rf ${WDir}/$mobileprovisionPlist

		#获取 TeamID
		TeamID=$($PlistBuddy -c "Print :com.apple.developer.team-identifier" ${WDir}/$entitlementsPlist)
		#获取 包名信息
		bundleID=$($PlistBuddy -c "Print :CFBundleIdentifier" $ipaPlist)
		#配置 application-identifier
		$PlistBuddy -c "Set :application-identifier ${TeamID}.${bundleID}" ${WDir}/$entitlementsPlist

		#配置 keychain-access-groups
		for (( i = 0; i < 9; i++ )); do
			if [[ -e  ${WDir}/${channelName}/Info.plist ]]; then
				keychain_access_groups=`$PlistBuddy -c "Print :keychain-access-groups:$i" ${WDir}/${channelName}/Info.plist`
			fi
			if [[ $keychain_access_groups ]]; then
				echo "提示：[keychain-access-groups]:$keychain_access_groups"
			else
				break
			fi
			read -p '按提示输入:' keychain_access_groups
			if [[ -n $keychain_access_groups ]]; then
				$PlistBuddy -c "Add :keychain-access-groups:$i string ${TeamID}.$keychain_access_groups" ${WDir}/$entitlementsPlist
			else
				i=`expr $i - 1`
			fi
		done

		#根据teamID搜索钥匙串信息
		certificates=$($Security find-identity -v -p codesigning | grep $TeamID)
		cerNumber=${#certificates[*]}

		if [[ $cerNumber -eq 1 ]]; then
			#取出证书
			keySign=${certificates[0]}
			keySign=${keySign#*)}
			#截取校验值
			# 075FF93C13 4EDDD0C310 75BE6F7993 BF8842DD85
			# keySign=${keySign::41} 
			#截取开发者信息
			keySign=${keySign#*\"}
			keySign=${keySign%\"*}

			echo "使用的钥匙串:$keySign"
		else
			echo "[错误]:钥匙串证书异常,请添加对应证书或删除无关的证书"
			continue
		fi

		#开始签名操作
		#通过Info.plist获取ipa包名称
		if [[ -z $CFBundleExecutable ]]; then
			CFBundleExecutable=$($PlistBuddy -c "Print :CFBundleExecutable" $ipaPlist)
		fi

		rm -rf ${WDir}/Payload/${CFBundleExecutable}.app/_CodeSignature/

		#复制到描述文件到ipa包
		cp ${WDir}/${mobileprovisionFile}.mobileprovision ${WDir}/Payload/${CFBundleExecutable}.app/embedded.mobileprovision

		#签名framework
		for file in ${WDir}/Payload/${CFBundleExecutable}.app/Frameworks/*.framework; do
			framwork=${file##*/}
			resignFwork=${framwork%.*}
			echo ${resignFwork}.framework

			$codesign -f -s "$keySign" ${WDir}/Payload/${CFBundleExecutable}.app/Frameworks/${resignFwork}.framework/${resignFwork}
		done

		#签名swift库
		for file in ${WDir}/Payload/${CFBundleExecutable}.app/Frameworks/*.dylib; do
			dylib=${file##*/}
			resignDylib=${dylib%.*}
			echo ${resignDylib}.dylib
			$codesign -f -s "$keySign" ${WDir}/Payload/${CFBundleExecutable}.app/Frameworks/${resignDylib}.dylib
		done

		#签名app
		$codesign -f -s "$keySign" --entitlements ${WDir}/$entitlementsPlist  ${WDir}/Payload/${CFBundleExecutable}.app

		#打包命名
		CFBundleDisplayName=$($PlistBuddy -c "Print :CFBundleDisplayName" $ipaPlist)
		CFBundleShortVersionString=$($PlistBuddy -c "Print :CFBundleShortVersionString" $ipaPlist)
		CFBundleVersion=$($PlistBuddy -c "Print :CFBundleVersion" $ipaPlist)

		#判断是否为Dis
		beta_reports_active=$($PlistBuddy -c "Print :beta-reports-active" ${WDir}/$entitlementsPlist)
		if [[ $beta_reports_active ]]; then
			beta='Dis'
		else
			beta='Hoc'
		fi

		if [[ -z $channelName ]];then
			newIpaName="${CFBundleDisplayName}_${CFBundleShortVersionString}(${CFBundleVersion})_${beta}"
		else
			newIpaName="${channelName}_${CFBundleDisplayName}_${CFBundleShortVersionString}(${CFBundleVersion})_${beta}"
		fi

		echo "新的ipa名字: $newIpaName"

		#压缩ipa包
		zip -r "${WDir}/${newIpaName}.ipa" ${WDir}/Payload/
	else
		echo '没有匹配的证书描述文件'
		continue
	fi
}

#拼接支付回调
getPayCallback()
{
	echo '支付回调:'
	if [[ ! $server_type ]]; then
		server_type=`$PlistBuddy -c "Print :server_type" $packConfig`
	fi
	if [[ ! $channelName ]]; then
		channelName=`$PlistBuddy -c "Print :channelName" $packConfig`
	fi
	if [[ ! $server_channel ]]; then
		server_channel=`$PlistBuddy -c "Print :server_channel" $packConfig`
	fi

	serverURL=`$PlistBuddy -c "Print :ServerURL:${server_type}" ${channelPath}/${payCallbackConfig}`
	channelURL=`$PlistBuddy -c "Print :ChannelURL:${channelName}" ${channelPath}/${payCallbackConfig}`

	if [[ $server_channel ]]; then
		payURL="${serverURL}/pay/${channelURL}/payCallback/$server_channel"
	else
		payURL="${serverURL}/pay/${channelURL}/payCallback/[渠道号]"
	fi
	echo "${newIpaName}:"
	echo $payURL
}

#清除生成的垃圾文件*************************************
cleanJunkFiles()
{
	read -p "确认清除打包生成的废弃文件(Y/N):" YN
	if [ "$YN" == 'y' ] || [ "$YN" == 'Y' ]; then
		rm -rf ${WDir}/$channelName
		rm -rf ${WDir}/Payload
		rm -rf $imagePath
		rm -rf $entitlementsPlist
		rm -rf $packConfig
		echo '退出成功(废弃文件清理完成)'
	else
		echo '退出成功(未清理废弃文件)'
	fi

	break
}

#创建配置文件
create_packConfig

#无限循环弹出菜单
while true; do
#功能菜单
echo '********************功能菜单*********************'
echo '[1].一键打包引导'
echo '[2].ipa包签名打包'
echo '[0].退出'
echo '************************************************'
read -p '请输入功能编号:' menuCode

case $menuCode in
1)
	importSDK
	setPlistParameter
	importAssets
	resign_ipa
	getPayCallback
	cleanJunkFiles
;;

2)
	resign_ipa
;;

0)
	cleanJunkFiles
;;

*)
	echo '输入有误,请重新输入!'
;;
esac

done

